#include "oglmanager.h"
#include <QDebug>
//#include <QKeyEvent>
#include "resourcemanager.h"

const QVector3D CAMERA_POSITION(0.0f, 0.0f, 3.0f);
const QVector3D LIGHT_POSITION(1.0f, 0.8f, 0.8f);
const QVector3D LIGHT_COLOR(1.0f, 1.0f, 1.0f);
const GLfloat LIGHT_SCALE = 0.1f;

OGLManager::OGLManager(GLuint w, GLuint h)
{
    width = w;
    height = h;

    core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();

    light = nullptr;
    camera = nullptr;

    for (GLuint i = 0; i != 1024; ++i)
    {
        keys[i] = GL_FALSE;
    }

    object = nullptr;
    isOpenLighting = GL_FALSE;
    isLineMode = GL_FALSE;
    modelScaling = 1.0f;
}

OGLManager::~OGLManager()
{
    if (light != nullptr)
    {
        delete light;
    }

    if (camera != nullptr)
    {
        delete camera;
    }

    if (object != nullptr)
    {
        delete object;
    }

    ResourceManager::clear();
}

GLboolean OGLManager::init()
{
    light = new Light();
    if (nullptr == light)
    {
        return GL_FALSE;
    }

    if (!light->init())
    {
        delete light;
        light = nullptr;

        return GL_FALSE;
    }

    camera = new Camera(CAMERA_POSITION);
    if (nullptr == camera)
    {
        delete light;
        light = nullptr;

        return GL_FALSE;
    }

    // light
    ResourceManager::loadShader("light", ":/shaders/res/shaders/light.vert", ":/shaders/res/shaders/light.frag");
    ResourceManager::getShader("light")->use().setVector3f("lightColor", LIGHT_COLOR);

    QMatrix4x4 model;
    model.translate(LIGHT_POSITION);
    model.scale(LIGHT_SCALE);
    ResourceManager::getShader("light")->use().setMatrix4f("model", model);

    ResourceManager::loadShader("object", ":/shaders/res/shaders/model.vert", ":/shaders/res/shaders/model.frag");

    // 开启状态
    core->glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    core->glEnable(GL_DEPTH_TEST);

    return GL_TRUE;
}

void OGLManager::resize(GLuint w, GLuint h)
{
    core->glViewport(0, 0, w, h);
}

void OGLManager::processInput(GLfloat deltaTime)
{
    if (keys[Qt::Key_W])
        camera->processKeyboard(FORWARD, deltaTime);
    if (keys[Qt::Key_S])
        camera->processKeyboard(BACKWARD, deltaTime);
    if (keys[Qt::Key_A])
        camera->processKeyboard(LEFT, deltaTime);
    if (keys[Qt::Key_D])
        camera->processKeyboard(RIGHT, deltaTime);
    if (keys[Qt::Key_E])
        camera->processKeyboard(UP, deltaTime);
    if (keys[Qt::Key_Q])
        camera->processKeyboard(DOWN, deltaTime);
}

void OGLManager::update(GLfloat deltaTime)
{
    if (this->isLineMode)
        core->glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    else
        core->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    QMatrix4x4 projection;
    projection.perspective(camera->zoom, (GLfloat)width / (GLfloat)height, 0.1f, 200.f);

    ResourceManager::getShader("light")->use().setMatrix4f("projection", projection);
    ResourceManager::getShader("light")->use().setMatrix4f("view", camera->getViewMatrix());

    if (object != nullptr)
    {
        ResourceManager::getShader("object")->use().setMatrix4f("projection", projection);
        ResourceManager::getShader("object")->use().setMatrix4f("view", camera->getViewMatrix());
//        ResourceManager::getShader("object")->use().setVector3f("viewPos", camera->position);

        QMatrix4x4 model;
        model.translate(LIGHT_POSITION);
        model.scale(modelScaling);
        ResourceManager::getShader("object")->use().setMatrix4f("model", model);
    }
}

void OGLManager::draw(GLfloat deltaTime)
{
    core->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    ResourceManager::getShader("light")->use();
    light->draw();

    if (object != nullptr)
    {
        ResourceManager::getShader("object")->use();
        object->draw();
    }
}

GLboolean OGLManager::loadModel(const QString &file)
{
    if (object != nullptr)
    {
        delete object;
        object = nullptr;
    }

    object = new Model();
    if (nullptr == object)
    {
        return GL_FALSE;
    }

    if (!object->loadModel(file))
    {
        delete object;
        object = nullptr;

        return GL_FALSE;
    }


//    ResourceManager::getShader("object")->use().setVector3f("objectColor", QVector3D(1.0f, 0.5f, 0.31f));
//    ResourceManager::getShader("object")->use().setVector3f("lightColor", LIGHT_COLOR);
//    ResourceManager::getShader("object")->use().setVector3f("lightPos", LIGHT_POSITION);

    return GL_TRUE;
}
